package com.edushare.common.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.cayenne.DataObjectUtils;

import com.edushare.common.orm.ORMInterface;
import com.edushare.common.util.StringUtil;
import com.edushare.common.vo.CourseDeptLink;
import com.edushare.common.vo.CourseInstances;
import com.edushare.common.vo.Courses;
import com.edushare.common.vo.Departments;
import com.edushare.common.vo.PrerequisiteLink;
import com.edushare.common.vo.Universities;
import com.edushare.common.vo.UniversityCourseLinks;
import com.edushare.common.vo.Users;

public class CoursesDAO extends CayenneBasedDAO {

	public CoursesDAO(ORMInterface ormInterface) {
		super(ormInterface);
	}

	public Courses createCourse(String name, Departments dept) {
		Courses course = new Courses();
		course.setCourseDesc("");
		course.setCourseName(name);
		course.setCreationTimestamp(new Date());
		course.setLectureHours(0);
		course.setPracticalHours(0);
		course.setStatus(Courses.COURSE_OFFERED);
		course.setTutorialHours(0);
		getDataContext().registerNewObject(course);
		UniversityCourseLinks ucl = new UniversityCourseLinks();
		ucl.setCourse(course);
		ucl.setUniversity(new DepartmentsDAO(ormInterface).getParent(dept));
		ucl.setCreationTimestamp(new Date());
		ucl.setUnivCourseAssnType(UniversityCourseLinks.UNIV_COURSE_OWNER);
		new CourseDeptLinkDAO(ormInterface).createCourseDeptLink(
				CourseDeptLink.DEPT_COURSE_OWNER, course, dept);
		getDataContext().registerNewObject(ucl);
		getDataContext().commitChanges();
		return course;
	}

	public Courses getCourseById(int pk) {
		return DataObjectUtils.objectForPK(getDataContext(), Courses.class, pk);
	}

	public String addCourseFB(String name, Departments dept) {
		if (getCourseByName(dept, name) != null)
			return "Course " + name + " already present in "
					+ dept.getDeptName();

		Courses c = getCourseByName(new DepartmentsDAO(ormInterface)
				.getParent(dept), name);
		if (createCourse(name, dept) != null) {
			if (c == null)
				return "New course " + name + " added to " + dept.getDeptName();
			else{
				Departments d = getParentDept(getCourseByName(
						new DepartmentsDAO(ormInterface).getParent(dept), name));
				return "Added new course"
						+ name
						+ ". A course with same name is also present department "
						+ d.getDeptName() + ".";
			}
		} else
			return "Unable to add course " + name + " due to unknown error";
	}
	
	public Courses getCourseByName(Universities univ, String name) {
		List<UniversityCourseLinks> ucl = univ.getLinkedCourses();
		for(UniversityCourseLinks u:ucl){
			if(u.getCourse().getCourseName().equals(name))
				return u.getCourse();
		}
		return null;
	}

	public Courses checkCourseUniqueness(Courses course) {
		Universities univ = getOwnerUniv(course);
		List<UniversityCourseLinks> uclList = univ.getLinkedCourses();
		for (UniversityCourseLinks ucl : uclList) {
			if (StringUtil.isValid(ucl.getCourse().getCourseCode())
					&& ucl.getCourse() != course
					&& ucl.getCourse().getCourseCode().equals(
							course.getCourseCode())) {
				return ucl.getCourse();
			}
		}
		return null;
	}

	public Courses getCourseByName(Departments dept, String name) {
		List<CourseDeptLink> cdL = dept.getCourseLinks();
		for (CourseDeptLink c : cdL) {
			if (c.getCourse().getCourseName().trim().equalsIgnoreCase(
					name.trim())
					&& c.getCourse().getStatus() != Courses.COURSE_WITHDRAWN
					&& c.getCourseDeptAssnType() == CourseDeptLink.DEPT_COURSE_OWNER)
				return c.getCourse();
		}
		return null;
	}

	public void removeCourse(Courses course) {
		if (course.getCourseInstances().size() > 0
				|| course.getDependentCourseLink().size() > 0) {
			CourseInstancesDAO ciDAO = new CourseInstancesDAO(ormInterface);
			if (ciDAO.isActive(course)) {
				CourseInstances ci = ciDAO.getActiveInst(course);
				ciDAO.closeAdministrative(ci);
			}
			course.setStatus(Courses.COURSE_WITHDRAWN);
		} else {
			List<PrerequisiteLink> links = course.getPrerequisiteLink();
			getDataContext().deleteObjects(links);
			List<UniversityCourseLinks> uclLinks = course.getUniversities();
			getDataContext().deleteObjects(uclLinks);
			List<CourseDeptLink> cdl = course.getDeptLinks();
			getDataContext().deleteObjects(cdl);
			getDataContext().deleteObject(course);
		}
		getDataContext().commitChanges();
	}

	public Departments getParentDept(Courses course) {
		List<CourseDeptLink> cdlList = course.getDeptLinks();
		for (CourseDeptLink c : cdlList) {
			if (c.getCourseDeptAssnType() == CourseDeptLink.DEPT_COURSE_OWNER)
				return c.getDepartment();
		}
		return null;
	}

	public List<Courses> getPrerequisites(Courses course) {
		List<PrerequisiteLink> pList = course.getPrerequisiteLink();
		List<Courses> prereqList = new ArrayList<Courses>();
		for (PrerequisiteLink p : pList) {
			prereqList.add(p.getPrerequisite());
		}
		return prereqList;
	}

	public void addPrereqToCourse(Courses course, Courses prereq) {
		if (course == null || prereq == null)
			return;
		if (course == prereq)
			return;
		List<Courses> courseList = getPrerequisites(course);
		if (courseList.contains(prereq))
			return;
		PrerequisiteLink p = new PrerequisiteLink();
		p.setCourse(course);
		p.setPrerequisite(prereq);
		getDataContext().registerNewObject(p);
		getDataContext().commitChanges();
		return;
	}

	public void removeCoursePrereq(Courses course, Courses prereq) {
		List<PrerequisiteLink> prL = course.getPrerequisiteLink();
		PrerequisiteLink pl = null;
		for (PrerequisiteLink p : prL) {
			if (p.getPrerequisite() == prereq)
				pl = p;
		}
		getDataContext().deleteObject(pl);
		getDataContext().commitChanges();
	}

	public List<Courses> getUnivCourses(Universities univ) {
		List<Courses> courseList = new ArrayList<Courses>();
		List<UniversityCourseLinks> uclList = univ.getLinkedCourses();
		for (UniversityCourseLinks ucl : uclList) {
			if (ucl.getUnivCourseAssnType() == UniversityCourseLinks.UNIV_COURSE_OWNER) {
				courseList.add(ucl.getCourse());
			}
		}
		return courseList;
	}

	public void closeAllCoures(Universities univ) {
		List<Courses> courseList = getUnivCourses(univ);
		CourseInstancesDAO dao = new CourseInstancesDAO(ormInterface);
		for (Courses course : courseList) {
			if (dao.isActive(course)) {
				dao.closeInst(course);
			}
		}
	}

	public boolean checkPrerequisites(Courses course, Users user) {
		EnrolmentsDAO eDAO = new EnrolmentsDAO(ormInterface);
		List<Courses> compCourses = eDAO.getUserCompletedCourses(user);
		List<Courses> prereqCourses = new PrerequisitesDAO(ormInterface)
				.getPrerequisites(course);
		Integer condition = course.getPrerequisitesCondition();
		if (condition == null)
			return true;
		if (condition == Courses.PREREQUISITE_COURSES_AND) {
			if (compCourses.containsAll(prereqCourses))
				return true;
			return false;
		} else {
			for (Courses c : prereqCourses) {
				if (compCourses.contains(c))
					return true;
			}
			return false;
		}
	}

	public Universities getOwnerUniv(Courses course) {
		List<UniversityCourseLinks> ucLList = course.getUniversities();
		for (UniversityCourseLinks ucl : ucLList) {
			if (ucl.getUnivCourseAssnType() == UniversityCourseLinks.UNIV_COURSE_OWNER)
				return ucl.getUniversity();
		}
		return null;
	}

	public boolean hasUserCompletedCourse(Users user, Courses course) {
		List<CourseInstances> cInst = course.getCourseInstances();
		EnrolmentsDAO eDAO = new EnrolmentsDAO(ormInterface);
		for (CourseInstances c : cInst) {
			if (eDAO.isUserPresent(c, user))
				return true;
		}

		return false;
	}

	public Courses getCourseByID(Universities univ, String courseId) {
		List<UniversityCourseLinks> ucLinks = univ.getLinkedCourses();
		for (UniversityCourseLinks ucl : ucLinks) {
			if (StringUtil.isValid(ucl.getCourse().getCourseCode()) &&
					ucl.getCourse().getCourseCode().toLowerCase().equals(
					courseId.toLowerCase()))
				return ucl.getCourse();
}
		return null;
	}
}
